﻿using System;
using System.Collections.Generic;
using System.Linq;
using Ur;
using Sargon;

using Pixels.Logic;
using Pixels.Interface;

namespace Pixels.Rendering
{
    public class PeopleDragger : State
    {

        public Canvas dragCanvas;

        public readonly WorldRenderer wr;
        public readonly Camera camera;
        public PeopleDragger(WorldRenderer wr) {
            this.wr = wr;
            this.camera = wr.camera;
            register_method(Trigger.tick, tick);
            register_method(Trigger.frame, render);
            register_method(Trigger.pre_frame, input);
            constructPeopleIcons();
            World.TurnStart += newTurn;
            dragCanvas = Interface.Interface.Instance.myCanvas;

        }

        void newTurn() {
            constructPeopleIcons();
        }

        void tick() {

        }

        void render() {
            Render.canvas = dragCanvas;
            foreach (var icon in peopleIcons.Values)icon.render();
        }

        void input() { // on input, update positions of everyone

            hilitIcon = null;

            var l = new List<Colonist>(World.Colony.idleColonists);
            l.Sort();
            int counter = 0;
            try { 
            foreach (var cc in l) {
                peopleIcons[cc.uniqueID].updateAsIdle(counter);
                counter++;
            }

            foreach (var structure in World.Colony.allStructures) {
                if (structure.AssignedColonists.Count > 0) {
                    var counter2 = 0;
                    var ll = new List<Colonist>(structure.AssignedColonists.ToArray());
                    ll.Sort();
                    foreach (var ccc in ll) peopleIcons[ccc.uniqueID].updateAsAssigned(structure, counter2++);
                }
            }

            foreach (var handle in World.Map.allExternalHandles) {
                var counter2 = 0;
                var list = new List<Colonist>(handle.ListColonists());
                list.Sort();
                foreach (var ccc in list) peopleIcons[ccc.uniqueID].updateAsAssigned(handle, counter2++);
            }
            } catch { }

            PeopleIcon nearest = null;
            float nearestD2 = 1200f;
            foreach (var icon in peopleIcons.Values) {
                var d2 = icon.screenPos.dist_squared(Mouse.coords);
                if (d2 < nearestD2) {
                    nearest = icon;
                    nearestD2 = d2;
                }
            }
            hilitIcon = nearest;

            if (Keys.Mouse1.pressed()) if (hilitIcon != null) startDrag(hilitIcon);
            if (Keys.Mouse1.released()) releaseDrag();



        }

        public void releaseDrag() {
            if (grabbedIcon != null) {
                if (wr.hilitTile != null) {
                    tryDropAtTile(grabbedIcon, wr.hilitTile);
                } else {
                    dropAtIdle(grabbedIcon);
                }
            }
            grabbedIcon = null;
        }

        void tryDropAtTile(PeopleIcon icon, Tile atTile) {
            if (icon.colonist.canAssignTo(atTile)) {
                icon.colonist.assignToTile(atTile);
            } else {
                dropAtIdle(icon);
                // do nothing
            }
        }

        void dropAtIdle(PeopleIcon icon) {
            icon.colonist.AssignedToTarget = null;

        }

        public void startDrag(PeopleIcon icon) {
            grabbedIcon = icon;
        }

        Dictionary<int, PeopleIcon> peopleIcons = new Dictionary<int, PeopleIcon>();

        public void constructPeopleIcons() {
            peopleIcons.Clear();
            foreach (var colonist in World.Colony.allColonists) createIcon(colonist);
        }

        PeopleIcon createIcon(Colonist c) {
            var icon = new PeopleIcon(c, this);
            peopleIcons.Add(c.uniqueID, icon);
            return icon;
        }

        internal PeopleIcon grabbedIcon = null;

        public Window idlePeopleWindow;

        public PeopleIcon hilitIcon = null;


        public class PeopleIcon
        {
            public enum State
            {
                idle,
                dragged,
                assigned
            }

            public State state;

            readonly PeopleDragger dragger;
            public readonly Colonist colonist;

            public PeopleIcon(Colonist colonist, PeopleDragger parent) {
                this.colonist = colonist;
                this.dragger = parent;
                this.state = colonist.Idle ? State.idle : State.assigned;
            }

            crds2 idleStart = new crds2(8, Screen.h - 20);
            crds2 idleOffset = new crds2(20, 0);
            public crds2 screenPos;
            float scale = 1f;

            internal void updateAsIdle(int positionInList) {
                screenPos = idleStart + idleOffset * positionInList;
                state = State.idle;
                if (dragger.grabbedIcon == this) { screenPos = Mouse.coords; state = State.dragged; }
                scale = 1f;
                

            }
            internal void updateAsAssigned(IAssignationTarget s, int positionInTarget) {
                if (dragger.grabbedIcon == this) { screenPos = Mouse.coords; state = State.dragged;  return; }
                var wc = s.getTile().worldCenter;
                wc.x -= 0.45f;
                wc.y += -0.32f + positionInTarget * 0.2f;
                screenPos = dragger.camera.project(wc);
                screenPos.y -= dragger.camera.zoom * 32f;
                scale = dragger.camera.zoom;
                state = State.assigned;
            }

            internal void render() {
                Sprite blip;
                if (state == State.assigned)    blip = Render.sprite(colonist.getIsometricIcon(), screenPos, scale, true);
                else                            blip = Render.sprite(colonist.getFrontalIcon(), screenPos, 1f, true);

                if (state != State.assigned) blip.zed = 1000;
                blip.color = new Color(1, 1, 1, 1);                                
            }
        }
    }

}
